home *** CD-ROM | disk | FTP | other *** search
- /* Copyright 2009, Boomtango.com. All Rights Reserved. */
- /* tracker.js
- * Responsible for tracking user behavior and sending to db
- */
-
- var EXTERNAL_TRACKERS = ['shopping', 'wikipedia', 'search', 'bookmark', 'contact', 'video'];
- var EXPORTED_SYMBOLS = ["boomtangoTracker"];
-
- function CustomCategory(name, keywords, regex) {
- this.name = name;
- this.name_plural = name;
- this.keywords = keywords;
- this.regex = regex;
- this.color = boomtangoTracker.app.generateColor();
- this.id = "custom." + encodeURIComponent(name);
- this.description = boomtangoTracker.app.getString("tracker.custom", keywords);
- }
- CustomCategory.prototype = {
- onLoadTracks: function(url, doc, referrer, content){
- var results = [];
- if(content && content.length){
- if(this.regex){
- if(content.match(this.keywords)){
- results.push({
- type: this.id
- });
- }
- } else {
- var a = this.keywords.split(',');
- var len = a.length;
- for(var x = 0; x < len; x++){
- if(content.indexOf(a[x]) >= 0){
- results.push({
- type: this.id
- });
- break;
- }
- }
- }
- }
- return results;
- }
- };
- var boomtangoTracker = {
- cc: Components.classes,
- ci: Components.interfaces,
- types: {
- web: {
- name: "Website",
- name_plural: "Websites",
- color: "#289f65",
- isInternal: true,
- preview: function(doc, node, data){
- var nopreview = true;
- if(data.preview && data.preview.length){
- var src = this.app.getThumb(parseInt(data.preview));
- if(src.length){
- var image = doc.createElement('image');
- image.setAttribute("src", src);
- image.className = "webthumb";
- node.appendChild(image);
- nopreview = false;
- }
- }
- if(nopreview){
- var vbox = doc.createElement('vbox');
- var spacer = doc.createElement('spacer');
- spacer.setAttribute('flex', '100');
- spacer.setAttribute('height', '80');
- vbox.appendChild(spacer);
-
- vbox.className = "nothumb";
- vbox.setAttribute("style", "width: 240px");
- var label = doc.createElement('label');
- label.setAttribute('value', this.app.getString('history.nopreview'));
- label.className = 'nopreview';
- vbox.appendChild(label);
- spacer = doc.createElement('spacer');
- spacer.setAttribute('flex', '100');
- spacer.setAttribute('height', '80');
- vbox.appendChild(spacer);
- node.appendChild(vbox);
- }
- }
- }
- },
- loadCategoryTrackers: function(){
- var list = this.app.getCustomCategoryList();
- var len = list.length;
- for(var x=0; x < len; x++){
- var item = list[x];
- this.createCategoryTracker(item.name, item.keywords, item.regex, true);
- }
- },
- loadCustomTrackers: function(){
- var file = Components.classes["@mozilla.org/file/directory_service;1"]
- .getService(Components.interfaces.nsIProperties)
- .get("ProfD", Components.interfaces.nsIFile);
- file.append("boomtango");
- file.append("trackers");
-
- var entries = file.directoryEntries;
- var jsregex = /^(.*)\.bct$/;
- var loader = Components.classes
- ["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Components.interfaces.mozIJSSubScriptLoader);
- var ios = Components.classes["@mozilla.org/network/io-service;1"].
- getService(Components.interfaces.nsIIOService);
- while(entries.hasMoreElements()){
- var entry = entries.getNext();
- var jsfile = entry.QueryInterface(Components.interfaces.nsIFile);
- var results = jsregex.exec(jsfile.leafName);
- if(results){
- this.app.log("tracker::loadCustom (" + jsfile.leafName + ")");
- var jsurl = ios.newFileURI(jsfile).spec;
- try {
- var newtype = {};
- loader.loadSubScript(jsurl, newtype);
- if(newtype.module){
- var id = "import." + results[1];
- this.types[id] = newtype.module;
- this.types[id].id = id;
-
- this.addMemberFuncs(this.types[id]);
- if(newtype.module.init){
- newtype.module.init(this.app.getTrackerData(id));
- }
- }
- } catch(e){
- this.app.log("error loading custom js: " + e.message);
- }
- }
- }
- },
- enableTracker: function(type, doEnable){
- if(this.app.getTrackerEnabled(type) != doEnable){
- this.app.setTrackerEnabled(type, doEnable);
-
- this.observer.notifyObservers(null, "boomtango-tracker-" + (doEnable ? "add" : "remove"), type);
- }
- },
- createCategoryTracker: function(name, keywords, regex, noAppUpdate){
- this.app.log("tracker::createCategory(" + name + ", (" + keywords + "), "
- + regex);
- var cat = new CustomCategory(name, keywords, regex);
- this.types[cat.id] = cat;
-
-
- if(!noAppUpdate){
- this.app.addCustomCategory(name, keywords, regex);
- this.observer.notifyObservers(null, "boomtango-tracker-add", cat.id);
- }
- return cat.id;
- },
- importTracker: function(importFile){
- var id = '????';
- var update = false;
- var file = Components.classes["@mozilla.org/file/directory_service;1"]
- .getService(Components.interfaces.nsIProperties)
- .get("ProfD", Components.interfaces.nsIFile);
- file.append("boomtango");
- file.append("trackers");
- var name = importFile.leafName;
- this.app.log("tracker::importTracker (" + name + ")");
- try {
- var file2 = Components.classes["@mozilla.org/file/directory_service;1"]
- .getService(Components.interfaces.nsIProperties)
- .get("ProfD", Components.interfaces.nsIFile);
- file2.append("boomtango");
- file2.append("trackers");
- file2.append(name);
- if(file2.exists()){
- update = true;
- try {
- file2.remove(false);
- } catch(e){
- this.app.log("error deleting custom js: " + e.message);
- }
- }
-
- importFile.copyTo(file, name);
- file.append(name);
- var ios = Components.classes["@mozilla.org/network/io-service;1"].
- getService(Components.interfaces.nsIIOService);
- var jsregex = /^(.*)\.bct$/;
- var results = jsregex.exec(name);
- if(results){
- var loader = Components.classes
- ["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Components.interfaces.mozIJSSubScriptLoader);
- var jsurl = ios.newFileURI(file).spec;
- var newtype = {};
- loader.loadSubScript(jsurl, newtype);
- if(newtype.module){
- var id = "import." + results[1];
- this.types[id] = newtype.module;
- if(!newtype.module.name_plural){
- newtype.module.name_plural = newtype.module.name;
- }
- this.types[id].id = id;
- this.addMemberFuncs(this.types[id]);
- if(newtype.module.init){
- newtype.module.init(null);
- }
- this.observer.notifyObservers(null, "boomtango-tracker-add", id);
- }
- }
- } catch(e){
- this.app.log("error importing custom js: " + e.message);
- }
- return update ? '????' : id;
- },
- addMemberFuncs: function(module){
- var app = this.app;
- var id = module.id;
- var getDataFunc = function(){
- return app.getTrackerData(id);
- };
- var setDataFunc = function(data){
- app.setTrackerData(id, data);
- };
- var log = function(s){
- app.log(s);
- };
- var debug = function(s){
- app.debug(s);
- };
-
- module.getData = getDataFunc;
- module.setData = setDataFunc;
- module.app = app;
- module.log = log;
- module.debug = debug;
- },
- deleteTracker: function(type){
- var a = type.split('.');
- if(!a.length){
- return;
- }
-
- switch(a[0]){
- case 'custom':
- var name = decodeURIComponent(a[1]);
- this.app.removeCustomCategory(name);
- var types = this.types;
- delete types[type];
- this.observer.notifyObservers(null, "boomtango-tracker-remove", type);
- break;
- case 'import':
- var file = Components.classes["@mozilla.org/file/directory_service;1"]
- .getService(Components.interfaces.nsIProperties)
- .get("ProfD", Components.interfaces.nsIFile);
- file.append("boomtango");
- file.append("trackers");
- file.append(a[1] + ".bct");
- try {
- file.remove(false);
- } catch(e){
- this.app.log("error deleting custom js: " + e.message);
- }
-
- var types = this.types;
- delete types[type];
- this.observer.notifyObservers(null, "boomtango-tracker-remove", type);
- break;
- }
-
- },
- init: function(app){
- this.app = app;
- this.storage = app.storage;
- this.purgatory = {};
- this.app.debug("tracker::init");
-
- var types = this.types;
- var len = EXTERNAL_TRACKERS.length;
- while(len--){
- this.app.debug("Adding " + EXTERNAL_TRACKERS[len]);
- Components.utils.import("resource://boomtango/trackers/" + EXTERNAL_TRACKERS[len] + ".js", types);
- }
- this.app.debug("Internal Trackers Loaded");
- for(var x in types){
- if(types.hasOwnProperty(x) && types[x].isInternal){
- types[x].app = this.app;
- types[x].name = this.app.getString("type.name." + x);
- types[x].name_plural = this.app.getString("type.name_plural." + x);
- types[x].description = this.app.getString("type.description." + x);
- }
- }
- this.loadCategoryTrackers();
- this.loadCustomTrackers();
- var history = this.cc["@mozilla.org/browser/nav-history-service;1"].
- getService(this.ci.nsINavHistoryService);
-
- this.observer = this.cc["@mozilla.org/observer-service;1"].
- getService(this.ci.nsIObserverService);
-
- history.addObserver(this, false);
- this.init = function(){};
- },
- importBrowserHistoryDone: function(callback){
- this.app.log("tracker:importDone");
- this._inImport = false;
- if(this.importData){
- this.importData.containerOpen = false;
- delete this.importData;
- }
- },
- importBrowserHistoryDoFTS: function(callback, loadFunc){
- this.app.log("tracker:importFTS(" + this.importDataCtr + ")");
- var storage = this.storage;
- var cont = this.importData;
- var len = this.importDataLength;
- if(this.importDataCtr >= len){
- callback(this.importDataCtr, len, false);
- return;
- }
- var node = cont.getChild(this.importDataCtr);
- var title = node.title;
- var url = node.uri;
- var starttime = Math.round(node.time / 1000);
- var self = this;
-
- loadFunc(url, function(doc, thumb){
- var content = "";
- if(doc){
- content = doc.body ? doc.body.textContent : "";
- }
- var tracks = [
- // add a general tab
- {
- type: "web",
- title: node.title,
- textContent: "",
- preview: thumb.toString()
- }
- ];
- var types = this.types;
- for( var x in types){
- if(types.hasOwnProperty(x)){
- var helper = types[x];
- if(helper.onLoadTracks && this.app.getTrackerEnabled(x)){
- var a = helper.onLoadTracks(url, doc);
- for(var x = 0; x < a.length; x++){
- tracks.push(a[x]);
- }
- }
- if(helper.onUnloadTracks){
- var a = helper.onUnloadTrack(url, doc);
- for(var x = 0; x < a.length; x++){
- tracks.push(a[x]);
- }
- }
- }
- }
-
- var len = tracks.length;
- for(var x = 0; x < len; x++){
- var t = tracks[x];
- if(t.content){
- content += " " + t.content;
- } else if(t.type == "shopping" && t.redirect_url){
- url = t.redirect_url;
- }
- }
- var ftsrowid = storage.addFTS(title, content, starttime,
- -1, url);
- storage.addTrackers(
- url,
- title,
- ftsrowid,
- starttime, starttime,
- tracks
- );
-
- self.importDataCtr++;
- if(self.importDataCtr >= len){
- self.importBrowserHistoryDone();
- callback(self.importDataCtr, len, false);
- } else {
- callback(self.importDataCtr, len, true);
- }
- });
- },
- importBrowserHistoryDo: function(callback){
- this.app.log("tracker::importBrowserHistoryDo");
- var storage = this.storage;
- var cont = this.importData;
- var len = this.importDataLength;
- var d = Date.now();
- for (; this.importDataCtr < len && Date.now() < d + 100; this.importDataCtr++) {
- if(!callback(this.importDataCtr, len)){
- this.importBrowserHistoryDone();
- return;
- }
- var node = cont.getChild(this.importDataCtr);
- var title = node.title;
- var url = node.uri;
- var starttime = Math.round(node.time / 1000);
- var content = "";
- var tracks = [
- // add a general tab
- {
- type: "web",
- title: node.title,
- textContent: "",
- preview: ""
- }
- ];
- var types = this.types;
- for( var x in types){
- if(types.hasOwnProperty(x)){
- var helper = types[x];
- if(helper.onLoadTracks && this.app.getTrackerEnabled(x)){
- var a = helper.onLoadTracks(url);
- for(var x = 0; x < a.length; x++){
- tracks.push(a[x]);
- }
- }
- if(helper.onUnloadTracks){
- var a = helper.onUnloadTracks(url);
- for(var x = 0; x < a.length; x++){
- tracks.push(a[x]);
- }
- }
- }
- }
- var tracklen = tracks.length;
- for(var x = 0; x < tracklen; x++){
- var t = tracks[x];
- if(t.content){
- content += " " + t.content;
- } else if(t.type == "shopping" && t.redirect_url){
- url = t.redirect_url;
- }
- }
- var ftsrowid = storage.addFTS(title, content, starttime,
- -1, url);
- storage.addTrackers(
- url,
- title,
- ftsrowid,
- starttime, starttime,
- tracks
- );
- }
- if(this.importDataCtr >= len){
- this.importBrowserHistoryDone();
- return false;
- } else {
- return true;
- }
- },
- importBrowserHistoryStart: function(){
- this.app.debug("tracker::importBrowserHistory");
- this._inImport = true;
- var historyService =
- Components.classes["@mozilla.org/browser/nav-history-service;1"]
- .getService(Components.interfaces.nsINavHistoryService);
-
- var options = historyService.getNewQueryOptions();
-
- options.queryType = options.QUERY_TYPE_HISTORY;
- options.resultType = options.RESULTS_AS_VISIT;
- options.sortingMode = options.SORT_BY_DATE_ASCENDING;
-
-
- var query = historyService.getNewQuery();
- var result = historyService.executeQuery(query, options);
- this.importData = result.root;
- this.importData.containerOpen = true;
- this.importDataCtr = 0;
- this.importDataLength = this.importData.childCount;
-
- this.app.debug("import count = " + this.importData.childCount );
- },
- onPageLoad: function(browserID, doc, thumb, referrer){
- var url = doc.location.href;
- this.app.log("tracker:onPageLoad (" + url + ")");
- var startTime = Date.now();
-
- var tracks = [
- // add a general tab
- {
- type: "web",
- title: doc.title,
- preview: thumb
- }
- ];
- var content = "";
- if(doc.body){
- var tmpBody = doc.body.cloneNode(true);
- Array.prototype.slice.call(
- tmpBody.getElementsByTagName('script')
- ).forEach(function(i) { i.parentNode.removeChild(i);});
-
- content = [tmpBody.textContent.replace(/\s+/g,' '),doc.title].join(' ');
- delete tmpBody;
- }
-
- var types = this.types;
- var trkctr = 0;
- for( var x in types){
- if(types.hasOwnProperty(x)){
- var helper = types[x];
- if(helper.onLoadTracks && this.app.getTrackerEnabled(x)){
- trkctr++;
- var a = helper.onLoadTracks(url, doc, referrer, content);
- for(var x = 0; x < a.length; x++){
- tracks.push(a[x]);
- }
- }
- }
- }
-
- var len = tracks.length;
- for(var x = 0; x < len; x++){
- var t = tracks[x];
- if(t.content){
- content += " " + t.content;
- } else if(t.type == "shopping" && t.redirect_url){
- url = t.redirect_url;
- }
- }
- var data = {
- url: url,
- browserID: browserID,
- tracks: [],
- title: doc.title,
- ftsrowid: this.storage.addFTS(doc.title, content, startTime, -1, url),
- startTime: startTime,
- endTime: -1,
- inSync: true
- };
- this.purgatory[browserID + "-" + url] = data;
- this.storage.addTrackers(url, data.title, data.ftsrowid,
- data.startTime, -1, tracks);
- this.observer.notifyObservers(null, "boomtango-visit-add",
- data.ftsrowid.toString());
-
- this.app.log("End Page Load: " + trkctr + ", " + (Date.now() - startTime));
- },
- onPageUnload: function(browserID, doc){
- var url = doc.location.href;
- var endTime = Date.now();
-
- var tracks = [];
-
- var types = this.types;
- for( var x in types){
- if(types.hasOwnProperty(x)){
- var helper = types[x];
- if(helper.onUnloadTracks && this.app.getTrackerEnabled(x)){
- var a = helper.onUnloadTracks(url, doc);
- for(var x = 0; x < a.length; x++){
- tracks.push(a[x]);
- }
- }
- }
- }
-
- var data = this.purgatory[browserID + "-" + url];
- if(data){
- data.endTime = endTime;
- this.storage.updateTrackerEnd(url, endTime, data.ftsrowid);
- this.storage.addTrackers(url, data.title, data.ftsrowid,
- data.startTime, data.endTime, tracks);
- this.observer.notifyObservers(null, "boomtango-visit-change",data.ftsrowid.toString());
-
- this.purgatory[browserID + "-" + url] = null;
- }
- },
- QueryInterface: function(iid) {
- if (iid.equals(this.ci.nsINavHistoryObserver) ||
- iid.equals(this.ci.nsINavHistoryObserver_MOZILLA_1_9_1_ADDITIONS) ||
- iid.equals(this.ci.nsISupports)) {
- return this;
- }
- throw Components.result.NS_ERROR_NO_INTERFACE;
- },
-
- //nsINavHistoryObserver
- onBeforeDeleteURI: function(){},
- onDeleteURI: function(uri){
- this.storage.deleteTrackersForURL(uri.spec);
- this.observer.notifyObservers(null, "boomtango-datachange",
- "delete");
- },
- onClearHistory: function(){},
- onBeginUpdateBatch: function(){},
- onEndUpdateBatch: function(){},
- onPageChanged: function(){},
- onPageExpired: function(){},
- onTitleChanged: function(){},
- onVisit: function(uri){
- }
- };
-
-